package com.zhj.helloframework.aop;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.ShadowMatch;

import java.lang.reflect.Method;

/**
 * @Author: zhj
 * @Description: 解析@Aspect注解中的切面表达式，并且定位需要被增强的目标
 * @Date: 2021/10/8 16:58
 * @Version: 1.0
 */
public class PointcutLocator {

    /**
     * Pointcut解析器，直接给它赋值上Aspectj的所有表达式，以便支持对众多表达式的解析
     * 对PointcutParser进行赋值，让其能对任何表达式进行解析，例如within和expression
     */
    private PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(PointcutParser.getAllSupportedPointcutPrimitives());

    /**
     * 表达式解析器
     */
    private PointcutExpression pointcutExpression;

    /**
     * 构造函数
     * @param expression @Aspect注解中的pointcut的值
     */
    public PointcutLocator(String expression) {
        // 将expression转换为表达式对象，后续可以使用该对象对指定的类及方法进行判断，看其是否是我们需要增强的对象
        this.pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    /**
     * 判断传入的Class对象是否是Aspect的目标代理类，即匹配Pointcut表达式(初筛：只能对类进行筛选)
     * @param targetClass 目标类
     * @return 是否匹配
     */
    public boolean roughMatches(Class<?> targetClass) {
        // 只能校验within，对于execution,call,get,set等无法校验的表达式，直接返回true
        // 如果pointcutExpression不是within类型的表达式，则返回true
        // 如果pointcutExpression是within类型的表达式，则对于不符合要求的类，就会返回false
        return pointcutExpression.couldMatchJoinPointsInType(targetClass);
    }

    /**
     * 判断传入的Method对象是否是Aspect的目标代理方法，即匹配Pointcut表达式(精筛)
     * @param method 目标方法
     * @return 是否匹配
     */
    public boolean accurateMatches(Method method) {
        // 对所有传入的方法对象进行筛选，如果不符合要求就返回false
        ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
        if (shadowMatch.alwaysMatches()) {
            return true;
        }
        return false;
    }
}
